#include "trigger_state.h"

//static variables
long TriggerState::tempIndex = -1;

TriggerState* TriggerState::update(long sampsPerChanRead)
{
    TriggerState* pState = this;
    TriggerState* old_pState = 0;
    long startIndex = 0;
    while (pState != old_pState){
            old_pState=pState;
            pState = pState->updateInstance(sampsPerChanRead, startIndex);
            startIndex = tempIndex == -1 ? 0 : tempIndex;
    }
    return pState;
}

bool TriggerState::operator==(const TriggerState &other)const
{
    if (&other == this)
        return true;
    else
        return false;
}
//! Global functions for printing trigger states -- implementation
std::ostringstream& operator<<(std::ostringstream& out, const TriggerState &state)
{
    out << state.getName();
    return out;
}
std::ostream& operator<<(std::ostream& out, const TriggerState &state)
{
    out << state.getName();
    return out;
}

TriggerState* PreTrigFilling::updateInstance(long sampsPerChanRead, long startIndex)
{
    availableSampPerChan += sampsPerChanRead;
    if (availableSampPerChan < preTrigSampsPerChan)
        return this;
    else {
        setTempIndex((preTrigSampsPerChan - availableSampPerChan) + sampsPerChanRead);
        return pPreTrigFull;
    }
}

inline bool risingCmp(double pt, double voltageLevel){return pt > voltageLevel;}
inline bool fallingCmp(double pt, double voltageLevel){return pt < voltageLevel;}
VoltageLevelLogic::VoltageLevelLogic(long trigSlope, double voltageLevel, ChanPointer pDataBuffer) :
    slope(trigSlope), level(voltageLevel), pData(pDataBuffer)
{
    if (trigSlope == RISING) pFun = risingCmp;  // arming condition opposite of trigger condition
        else if (trigSlope == FALLING) pFun = fallingCmp;
            else assert(false);  // should be true or false
}

long VoltageLevelLogic::operator()(long sampsPerChanRead, long index)
{
    long temp = -1;
    double pt;
    while (index < sampsPerChanRead){
        pt = pData[index];
        if (pFun(pt, level)){               // could only pass in point
            temp = index;
            break;
        }
        index++;
    }
    return temp;
}
PreTrigFull::PreTrigFull(TriggerState* pArmedState, long triggerSlope, double armVoltage, ChanPointer pData) :
    TriggerState(), pArmed(pArmedState), arm((triggerSlope == RISING)? FALLING : RISING, armVoltage, pData)
{}

TriggerState* PreTrigFull::updateInstance(long sampsPerChanRead, long startIndex)
{
    setTempIndex(arm(sampsPerChanRead, startIndex));
    if (getTempIndex() == -1)
        return this;
    return pArmed;
}

TriggerState* Armed::updateInstance(long sampsPerChanRead, long startIndex)
{
    setTempIndex(trig(sampsPerChanRead, startIndex));
    if (getTempIndex() == -1)
        return this;
    return pTriggered;
}
